/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2023-2023. All rights reserved.
 */

import { MetricFactory } from '../metric-factory.js';
import { MetricService } from '../metric-service.js';

import { BaseEvent, EventAdditional, EventBody, EventHead, MetricEventType } from './base-event.js';
import { DurationEvent } from './duration-event.js';
import { LogEvent, MetricLogType } from './log-event.js';

export class ContinualEventAdditional implements EventAdditional {
  totalTime: number;
  frequency: number;
  children: string[];
  parent?: string;
  logId?: string;
  detailId?: string;

  constructor(totalTime?: number, frequency?: number) {
    this.totalTime = totalTime ?? 0;
    this.frequency = frequency ?? 0;
    this.children = [];
  }
}

export class ContinualEvent extends BaseEvent {
  additional: ContinualEventAdditional;

  constructor(id: string, name: string, description: string, pid: number, tid: string, totalTime?: number, frequency?: number) {
    super(new EventHead(id, name, description, MetricEventType.CONTINUAL), new EventBody(pid, tid));
    this.additional = new ContinualEventAdditional(totalTime, frequency);
  }

  setParent(parentId: string) {
    this.additional.parent = parentId;
  }

  getParent() {
    return this.additional.parent;
  }

  addChild(childId: string) {
    this.additional.children.push(childId);
  }

  getChildren() {
    return this.additional.children;
  }

  createSubEvent(name: string, description: string) {
    const child = MetricFactory.createContinualEvent(name, description);
    child.setParent(this.getId());
    this.addChild(child.getId());
    return child;
  }

  setLog(name: string, type: MetricLogType, description?: string) {
    const logEvent = MetricFactory.createLogEvent(name, type, this.getTid(), description);
    logEvent.setContinualId(this.getId());
    this.additional.logId = logEvent.getId();
    logEvent.setStartTime(this.body.startTime);
    logEvent.setEndTime(this.body.endTime);

    this.setParentLog(logEvent);
    this.setChildrenLog(logEvent);
  }

  setParentLog(logEvent: LogEvent) {
    const parentEvent = MetricService.getInstance().getEventById(this.additional.parent);
    if (parentEvent instanceof ContinualEvent || parentEvent instanceof DurationEvent) {
      const parentLog = MetricService.getInstance().getEventById(parentEvent.additional.logId);
      if (parentLog instanceof LogEvent) {
        parentLog.addChild(logEvent.getId());
        logEvent.setParent(parentLog.getId());
      }
    }
  }

  setDetail(name: string) {
    const logEvent = MetricFactory.createLogEvent(name, MetricLogType.DETAIL, this.getTid());
    logEvent.setContinualId(this.getId());
    this.additional.detailId = logEvent.getId();
  }

  setChildrenLog(logEvent: LogEvent) {
    this.additional.children.forEach((child) => {
      const childEvent = MetricService.getInstance().getEventById(child);
      if (childEvent instanceof ContinualEvent) {
        logEvent.addChild(childEvent.additional.logId);
        const childLog = MetricService.getInstance().getEventById(childEvent.additional.logId);
        if (childLog instanceof LogEvent) {
          childEvent.setParentLog(childLog);
        }
      }
    });
  }
}
